package com.ctsi.commons.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.*;

public final class UtilMisc {
	private static final Logger log = LoggerFactory.getLogger(UtilMisc.class);
	
	
	public static final int sysProcessors= Runtime.getRuntime().availableProcessors();

	public static final String checkEmpty(final String string) {
		if (string != null)
			return string;
		else
			return "";
	}

	public static final boolean checkBoolean(final String str) {
		return checkBoolean(str, false);
	}

	public static final boolean checkBoolean(final String str, final boolean defaultValue) {
		if (defaultValue) {
			return !"false".equals(str);
		} else {
			return "true".equals(str);
		}
	}

	/**
	 * 四舍五入保留scale位小数
	 * 
	 * @param scale
	 * @param pDouble
	 * @return
	 */
	public static double getScale(final int scale, final double pDouble) {
		BigDecimal bd = new BigDecimal(pDouble);
		BigDecimal bd1 = bd.setScale(scale, BigDecimal.ROUND_HALF_UP);
		return bd1.doubleValue();

	}

	/**
	 * 四舍五入取整:
	 * 
	 * @param value
	 * @return
	 */
	public static int getInt(final double value) {
		return new BigDecimal(value).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();

	}

	public static int getIntthrow(final float value) {
		return (int) Math.floor(value);

	}

	public static int getIntceil(final float value) {
		return (int) Math.ceil(value);

	}

	public static <T> Iterator<T> toIterator(final Collection<T> col) {
		if (col == null)
			return null;
		else
			return col.iterator();
	}

	/**
	 * 建立一个map
	 * 
	 * @return The resulting Map
	 */
	public static <V, V1 extends V> Map<String, V> toMap(final String name1, final V1 value1) {
		Map<String, V> fields = new HashMap<String, V>();

		fields.put(name1, value1);

		return fields;

	}

	/**
	 * 建立一个map
	 * 
	 * @return The resulting Map
	 */
	public static <V, V1 extends V, V2 extends V> Map<String, V> toMap(final String name1,final  V1 value1,final  String name2,final  V2 value2) {
		Map<String, V> fields = new HashMap<String, V>();

		fields.put(name1, value1);
		fields.put(name2, value2);

		return fields;

	}

	/**
	 * 建立一个map
	 * 
	 * @return The resulting Map
	 */
	public static <V, V1 extends V, V2 extends V, V3 extends V> Map<String, V> toMap(final String name1, final V1 value1, final String name2, final V2 value2, final String name3,final  V3 value3) {
		Map<String, V> fields = new HashMap<String, V>();

		fields.put(name1, value1);
		fields.put(name2, value2);
		fields.put(name3, value3);

		return fields;

	}

	public static <K, V> String printMap(final Map<? extends K, ? extends V> theMap) {
		final StringBuilder theBuf = new StringBuilder(theMap.size() << 3);
		final String lines = System.getProperty("line.separator");
		for (Map.Entry<? extends K, ? extends V> entry : theMap.entrySet()) {
			theBuf.append(entry.getKey());
			theBuf.append(" --> ");
			theBuf.append(entry.getValue());
			theBuf.append(lines);
		}
		return theBuf.toString();
	}

	public static <T> Set<T> collectionToSet(final Collection<T> c) {
		if (c == null)
			return null;
		Set<T> theSet = null;
		if (c instanceof Set<?>) {
			theSet = (Set<T>) c;
		} else {
			theSet = new HashSet<T>(c.size());
			c.remove(null);
			theSet.addAll(c);
		}
		return theSet;
	}

	/**
	 * 建立一个map
	 * 
	 * @return The resulting Map
	 */
	@SuppressWarnings("unchecked")
	public static <V> Map<String, V> toMap(V... data) {
		if (data == null) {
			return null;
		}
		if (data.length % 2 == 1) {
			throw new IllegalArgumentException("You must pass an even sized array to the toMap method");
		}
		Map<String, V> map = new HashMap<String, V>();
		for (int i = 0; i < data.length;) {
			map.put((String) data[i++], data[i++]);
		}
		return map;
	}

	public static List<Map<String, Object>> toListMap(final List<?> list) {
		return toListMap(list, null);
	}

	public static <T> List<Map<String, Object>> toListMap(final List<T> list,final  BeanToMap<T> bMap) {
		assert (list != null);
		int len = list.size();
		List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(len);
		for (int i = 0; i < len; i++) {
			Map<String, Object> map = toMap(list.get(i));
			if (bMap != null)
				bMap.setInfo(map, list.get(i));
			result.add(i, map);
		}
		return result;
	}

	public interface BeanToMap<T> {

		void setInfo(Map<String, Object> beanMap, T bean);

	}

	/**
	 * java bean 转换为Map
	 * 
	 * @param bean
	 * @return
	 */
	public static Map<String, Object> toMap(final Object bean) {
		if (bean == null)
			return null;
		Map<String, Object> result = new HashMap<String, Object>();

		Class<?> beanClass = bean.getClass();
		Field[] fields = UtilObject.getAllPublicReadFields(beanClass);
		for (int i = 0; i < fields.length; i++) {
			try {
				String fieldName = fields[i].getName();
				PropertyDescriptor descriptor = UtilObject.getPropertyDescriptor(beanClass, fieldName);
				if (descriptor == null) {
					continue;
				}
				Method readMethod = descriptor.getReadMethod();
				if (readMethod == null) {
					continue;
				}
				Object value = readMethod.invoke(bean);
				if (value != null) {
					if (isPrimitive(value.getClass()) || value.getClass().getPackage().getName().startsWith("java."))
						result.put(fieldName, value);
					else
						result.put(fieldName, toMap(value));
				} else {
					result.put(fieldName, value);
				}

			} catch (Exception e) {
				throw new RuntimeException(e);
			}

		}

		return result;
	}

	public final static boolean isPrimitive(final Class<?> cls) {
		return cls.isArray() || cls.isPrimitive() || cls == Boolean.class || cls == Byte.class || cls == Character.class || cls == Short.class || cls == Integer.class || cls == Long.class || cls == Float.class || cls == Double.class;
	}

	public static void copyBeanToMap(final Object bean, final Map<String, Object> m) {
		Field[] fields = UtilObject.getAllPublicReadFields(bean.getClass());
		for (int i = 0; i < fields.length; i++) {

			String fieldName = fields[i].getName();

			Object value = UtilObject.getBeanValue(bean, fieldName);

			m.put(fieldName, value);

		}
	}

	/**
	 * map 给bean赋值
	 * 
	 * @param m
	 * @param bean
	 * @param ignoreCase
	 */
	public static void copyMapToBean(final Map<?, ?> m, final Object bean, final boolean ignoreCase) {
		Reference reference = new Reference();
		for (Map.Entry<?, ?> en : m.entrySet()) {

			Object key = en.getKey();
			Object value = null;
			if (haseField(bean, key.toString(), ignoreCase, reference)) {

				Object mapValue = en.getValue();
				try {
					if ("long".equals(reference.javaType) || "java.lang.Long".equals(reference.javaType)) {
						if (mapValue instanceof String) {
							if (UtilValidate.isNotEmpty((String) mapValue)) {
								if (UtilValidate.isDate((String) mapValue) && ("long".equalsIgnoreCase(reference.javaType) || "java.lang.Long".equals(reference.javaType)) ) {
									long time = UtilDateTime.toDate((String) mapValue).getTime();

									UtilObject.setBeanValue(bean, reference.fieldName, new Long(time));
									continue;
								}

							} else {
								// 默认0
								if ("long".equalsIgnoreCase(reference.javaType) || "java.lang.Long".equals(reference.javaType)) {
									UtilObject.setBeanValue(bean, reference.fieldName, Long.valueOf(0));
								}

								else {
									UtilObject.setBeanValue(bean, reference.fieldName, null);
								}
								continue;
							}
						}

					}
					value = ObjectType.simpleTypeConvert(mapValue, reference.javaType, UtilDateTime.defaultDatePattern, null);
					UtilObject.setBeanValue(bean, reference.fieldName, value);
				} catch (Exception e) {
					// e.printStackTrace();
					if (value != null) {
						throw new RuntimeException("set field " + reference.fieldName + " error ,value class is " + value.getClass().getName() + " field type is " + reference.javaType, e);
					}

					else {
						throw new RuntimeException("set field " + reference.fieldName + "error ,value is null, field type is " + reference.javaType, e);
					}
				}
			}
		}
	}

	private static class Reference {
		 String fieldName;
		 String javaType;
	}

	private static boolean haseField(final Object bean, final String fieldName,final boolean ignoreCase, Reference reference) {
		Field[] fields = UtilObject.getAllPublicReadFields(bean.getClass());
		for (int i = 0; i < fields.length; i++) {
			if (ignoreCase) {
				if (fields[i].getName().equalsIgnoreCase(fieldName)) {

					reference.fieldName = fields[i].getName();
					reference.javaType = fields[i].getType().getName();
					return true;
				}
			} else {
				if (fields[i].getName().equals(fieldName)) {
					reference.fieldName = fields[i].getName();
					reference.javaType = fields[i].getType().getName();
					return true;
				}
			}

		}
		return false;
	}

	public static <T> List<T> toList(final T obj1) {
		List<T> list = new ArrayList<T>(4);

		list.add(obj1);
		return list;
	}

	/**
	 * 建立两个数据的list
	 * 
	 * @return The resulting List
	 */
	public static <T> List<T> toList(final T obj1, final T obj2) {
		List<T> list = new ArrayList<T>(6);

		list.add(obj1);
		list.add(obj2);
		return list;
	}

	/**
	 * 建立一个list
	 * 
	 * @return The resulting List
	 */
	public static <T> List<T> toList(final T obj1,final  T obj2,final  T obj3) {
		List<T> list = new ArrayList<T>(6);

		list.add(obj1);
		list.add(obj2);
		list.add(obj3);
		return list;
	}

	/**
	 * 建立一个list
	 * 
	 * @return The resulting List
	 */
	public static <T> List<T> toList(final T obj1,final  T obj2, T obj3, final T obj4) {
		List<T> list = new ArrayList<T>(6);

		list.add(obj1);
		list.add(obj2);
		list.add(obj3);
		list.add(obj4);
		return list;
	}

	/**
	 * 建立一个list,并加入数据
	 * 
	 * @return The resulting List
	 */
	public static <T> List<T> toList(T obj1, T obj2, T obj3, T obj4, T obj5) {
		List<T> list = new ArrayList<T>(8);

		list.add(obj1);
		list.add(obj2);
		list.add(obj3);
		list.add(obj4);
		list.add(obj5);
		return list;
	}

	public static <T> List<T> toList(T obj1, T obj2, T obj3, T obj4, T obj5, T obj6) {
		List<T> list = new ArrayList<T>(8);

		list.add(obj1);
		list.add(obj2);
		list.add(obj3);
		list.add(obj4);
		list.add(obj5);
		list.add(obj6);
		return list;
	}

	public static <T> List<T> toList(Collection<T> collection) {
		if (collection == null)
			return null;
		if (collection instanceof List<?>) {
			return (List<T>) collection;
		} else {
			List<T> list = new ArrayList<T>(collection.size());
			list.addAll(collection);
			return list;
		}
	}
	@SafeVarargs
	public static <T> List<T> toListArray(T... data) {
		if (data == null) {
			return null;
		}
		List<T> list = new ArrayList<T>(data.length);
		for (T value : data) {
			list.add(value);
		}
		return list;
	}

	public static long toLong(final Object value) {
		if (value != null) {
			if (value instanceof Long) {
				return ((Long) value).longValue();
			}
	        if (value instanceof Number) {
	            return new Long(((Number)value).longValue());
	        }
			if (value instanceof String) {
				return Long.parseLong((String) value);
			}
		}
		return 0;
	}

	public static double toDouble(final Object value) {
		if (value != null) {
			if (value instanceof Double) {
				return ((Double) value).doubleValue();
			} else if (value instanceof String) {
				return Double.parseDouble((String) value);
			}
		}
		return 0.0;
	}

	/**
	 * 转化String 为Locale object
	 * 
	 * @param localeString
	 *            本地标记 (zh_CN)
	 * @return Locale The new Locale object or null if no valid locale can be interpreted
	 */
	public static Locale parseLocale(final String localeString) {
		if (localeString == null || localeString.length() == 0) {
			return null;
		}

		Locale locale = null;
		if (localeString.length() == 2) {
			// two letter language code
			locale = new Locale(localeString);
		} else if (localeString.length() == 5) {
			// positions 0-1 language, 3-4 are country
			String language = localeString.substring(0, 2);
			String country = localeString.substring(3, 5);
			locale = new Locale(language, country);
		} else if (localeString.length() > 6) {
			// positions 0-1 language, 3-4 are country, 6 and on are special
			// extensions
			String language = localeString.substring(0, 2);
			String country = localeString.substring(3, 5);
			String extension = localeString.substring(6);
			locale = new Locale(language, country, extension);
		} else {
			
			log.error("Do not know what to do with the localeString [" + localeString + "], should be length 2, 5, or greater than 6, returning null");
		}

		return locale;
	}

	/**
	 * 转化为Locale
	 * 
	 * @param localeObject
	 *            可以是String,Local ,null
	 * @return
	 */
	public static Locale ensureLocale(Object localeObject) {
		if (localeObject != null && localeObject instanceof String) {
			localeObject = UtilMisc.parseLocale((String) localeObject);
		}
		if (localeObject != null && localeObject instanceof Locale) {
			return (Locale) localeObject;
		} else {
			return Locale.getDefault();
		}
	}




	/**
	 * 读取InputStream数据为byte[] ,InputStream 会被关闭
	 * 
	 * @param is
	 * @return
	 */
	public static byte[] getData(final InputStream is) {
		ByteOutputStream bos = null;
		byte[] data = null;
		try {
			int size = is.available();
			if (size < 1024)
				size = 1024;
			bos = new ByteOutputStream(size);
			UtilFile.copyNoClose(is, bos);
			data = bos.toByteArray();
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			closeObjNoExc(is);
		}

		return data;
	}

	/**
	 * 注意没有关闭reader
	 * 
	 * @param reader
	 * @return
	 * @throws IOException
	 */
	public static byte[] toByteArray(final Reader reader) throws IOException {

		ByteOutputStream outputStream = new ByteOutputStream();
		Writer writer = new OutputStreamWriter(outputStream);
		try {
			copy(reader, writer);
		} finally {
			writer.close();
		}

		return outputStream.toByteArray();
	}

	public static byte[] toByteArray(final Reader reader, final long length) throws IOException {

		ByteOutputStream outputStream = new ByteOutputStream();
		Writer writer = new OutputStreamWriter(outputStream);
		try {
			copy(reader, writer, length);
		} finally {
			writer.close();
		}

		return outputStream.toByteArray();
	}

	public static void copy(final Reader reader, final Writer writer, final long length) throws IOException {

		char[] buf = new char[UtilFile.BufferSize];
		int read = -1, readonce = buf.length;
		long rest = length;

		while (true) {

			if (readonce > rest)
				readonce = (int) rest;
			read = reader.read(buf, 0, readonce);

			if (read == -1) {
				break;
			}
			rest -= read;
			writer.write(buf, 0, read);

			if (rest <= 0) {

				break;
			}
		}

	}

	public static void copy(final Reader reader, final Writer writer) throws IOException {

		int i = 0;
		char[] chars = new char[UtilFile.BufferSize];
		do {
			i = reader.read(chars);
			if (i != -1) {
				writer.write(chars, 0, i);
			}
		} while (i != -1);
	}

	public static byte[] toByteArray(final InputStream inputStream) throws IOException {

		ByteOutputStream outputStream = new ByteOutputStream();

		UtilFile.copyStreamNoClose(inputStream, outputStream);

		return outputStream.toByteArray();
	}

	/**
	 * 转化为inputstream,注意是非同步stream
	 * 
	 * @param bb
	 * @return
	 * @throws IOException
	 */
	public static InputStream toInputStream(final ByteBuffer bb) {
		int len = bb.remaining();
		if (bb.hasArray()) {

			final int arrayOffset = bb.arrayOffset() + bb.position();
			return new ByteInputStream(bb.array(), arrayOffset, len);
		} else {
			byte[] b = new byte[len];
			bb.get(b);
			return new ByteInputStream(b);
		}

	}

	public static byte[] toByteArray(final InputStream inputStream, final long length) throws IOException {

		ByteOutputStream outputStream = new ByteOutputStream();

		UtilFile.copy(inputStream, outputStream, length);

		return outputStream.toByteArray();
	}

	public static final ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		} catch (Throwable ex) {

		}
		if (cl == null) {

			cl = UtilMisc.class.getClassLoader();
		}
		return cl;
	}

	public static final boolean closeObjNoExc(final Closeable o) {
		if (o != null) {
			try {
				o.close();

			} catch (Exception e) {
				log.info("closeObjNoExc error", e);
				log.warn("closeObjNoExc error :{}", e.toString());
				return false;
			}
		}
		return true;
	}
	public static final boolean closeObjNoExc(final AutoCloseable o) {
		if (o != null) {
			try {
				o.close();

			} catch (Exception e) {
				log.info("closeObjNoExc error", e);
				log.warn("closeObjNoExc error :{}", e.toString());
				return false;
			}
		}
		return true;
	}	
}
